/*
 * PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
 *
 * Authors: Sumana Srinivasan, NeXT Inc.;            sumana_srinivasan@next.com
 *          Terence Parr, Parr Research Corporation; parrt@parr-research.com
 *          Russell Quong, Purdue University;        quong@ecn.purdue.edu
 *
 * VERSION 1.2
 *
 * SOFTWARE RIGHTS
 *
 * This file is a part of the ANTLR-based C++ grammar and is free
 * software.  We do not reserve any LEGAL rights to its use or
 * distribution, but you may NOT claim ownership or authorship of this
 * grammar or support code.  An individual or company may otherwise do
 * whatever they wish with the grammar distributed herewith including the
 * incorporation of the grammar or the output generated by ANTLR into
 * commerical software.  You may redistribute in source or binary form
 * without payment of royalties to us as long as this header remains
 * in all source distributions.
 *
 * We encourage users to develop parsers/tools using this grammar.
 * In return, we ask that credit is given to us for developing this
 * grammar.  By "credit", we mean that if you incorporate our grammar or
 * the generated code into one of your programs (commercial product,
 * research project, or otherwise) that you acknowledge this fact in the
 * documentation, research report, etc....  In addition, you should say nice
 * things about us at every opportunity.
 *
 * As long as these guidelines are kept, we expect to continue enhancing
 * this grammar.  Feel free to send us enhancements, fixes, bug reports,
 * suggestions, or general words of encouragement at parrt@parr-research.com.
 * 
 * NeXT Computer Inc.
 * 900 Chesapeake Dr.
 * Redwood City, CA 94555
 * 12/02/1994
 * 
 * Restructured for public consumption by Terence Parr late February, 1995.
 *
 * DISCLAIMER: we make no guarantees that this grammar works, makes sense,
 *             or can be used to do anything useful.
 */
/* 2001-2002
 * Version 1.0
 * This C++ grammar file has been converted from PCCTS to run under 
 *  ANTLR to generate lexer and parser in C++ code by
 *  Jianguo Zuo and David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 */
/* 2003
 * Version 2.0 was published by David Wigg in September 2003
 */
/* 2004
 * Version 3.0 July 2004
 * This is version 3.0 of the C++ grammar definition for ANTLR to 
 *  generate lexer and parser in C++ code updated by
 *  David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 */
/* 2005
 * Version 3.1 November 2005
 * Updated by David Wigg at London South Bank University
 *
 */
/* 2007
 * Version 3.2 November 2007
 * Updated by David Wigg at London South Bank University
 *
 * wiggjd@bcs.ac.uk
 * blackse@lsbu.ac.uk
 *
 * See MyReadMe.txt for further information
 *
 * This file is best viewed in courier font with tabs set to 4 spaces
 */
/* -- 2010 --
 * Version 4.0.1 August 2010
 * Modified and reworked to compile with ANTLR 3.2
 *  by Ramin Zaghi
 * 
 * Please note that this is the first public release
 *  for ANTLR 3.2; This does not comiple with any older
 *  versions of ANTLR. This may also have some missing 
 *  features compared to the 2007 update by David Wigg.
 *  I am publishing this work only to make this first
 *  ANTLR 3.2 update  available  to  the  community
 *  however if you are interested in a more complete 
 *  work please take a look at David's 2007 update.
 * 
 *  I emphasize that this new update needs more work
 *  and can be restructured to make it more developer
 *  friendly. The project file is a MSVS2008 project
 *  file and it only includes a "Debug" configuration.
 *  
 *  You may send your comments to < antlr3_cpp_parser@taggedprogramming.com >
 *  
 *
 * Version 4.1.0  January 2011
 *  Functional ANTLR 3.2 parser. 
 *   Updated by Aurelian Melinte <ame01@gmx.net> with the 
 *   assistance of David Wigg<wiggjd@bcs.org.uk>
 */






grammar CPP_grammar_;

options
{	
	language = C;
}

tokens 
{
	OPERATOR = 'operator';
}

@parser::header
{
	extern "C++"
	{
	#include "header_file.h"
	}
	//typedef CPP_grammar_Parser_function_specifier_return FS_ret_t;
	//typedef CPP_grammar_Parser_type_specifier_return TS_ret_t;
}

@parser::members
{
	extern "C++"
	{
	#include "members_file.h"
	}
}

@lexer::header
{
	extern "C++"
	{
	#include "header_file.h"
	}
}

@lexer::members
{
	//#include "members_file.h" // already in parser source code
}


//translation_unit
translation_unit
	@init {
		CPPParser__init();
	}
	:	{enterExternalScope();}
		(external_declaration)*  EOF
		{exitExternalScope();}
	;

//external_declaration	Note: These comment lines are provided to assist searching for productions
external_declaration	
	scope { 
		char *pScopeOverrideBuf;
	}
	@declarations {
		//FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		lineNo = LT(1)->line;
		boolean K_and_R;
		K_and_R = FALSE;
		//FunctionSpecifier
		fs = fsInvalid;	// inline,virtual,explicit
		//in_user_file = in_user_file_deferred;
		$external_declaration::pScopeOverrideBuf = bufScopeOverrideScope; 
	}
	:
	(
		// Template explicit specialisation
		('template' LESSTHAN GREATERTHAN)=>
		{if(statementTrace>=1) 
			printf("\%d external_declaration template explicit-specialisation\n",LT(1)->line);
		}
		'template' LESSTHAN GREATERTHAN external_declaration

	|
		// All typedefs
		('typedef')=>
		(
			('typedef' 'enum')=>
			{if(statementTrace>=1) 
				printf("\%d external_declaration Typedef enum type\n",LT(1)->line);
			}
			'typedef' enum_specifier {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|
			(declaration_specifiers function_declarator[0] SEMICOLON)=>	// DW 11/02/05 This may not be possible
			{if(statementTrace>=1) 
				printf("\%d external_declaration Typedef function type\n",LT(1)->line);
			}
			declaration
		|
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if(statementTrace>=1) 
				printf("\%d external_declaration Typedef variable type\n",LT(1)->line);
			}
			declaration
		|
			('typedef' class_specifier)=>
			{if(statementTrace>=1) 
				printf("\%d external_declaration Typedef class type\n",LT(1)->line);
			}
			'typedef' class_decl_or_def[bufScopeOverrideScope, fs] {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		)
		
	|	
		// Class template declaration or definition
		(template_head (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("\%d external_declaration Templated class decl or def\n",LT(1)->line);
		}
		template_head (fs = function_specifier)* class_decl_or_def[bufScopeOverrideScope, fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}	// declaration
	|
		// Templated functions and constructors matched here.
		{beginTemplateDeclaration();}
		template_head
		(  
			// templated forward class decl, init/decl of static member in template
			(declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();})=>
			{if (statementTrace>=1) 
				printf("\%d external_declaration Templated class forward declaration\n",LT(1)->line);
			}
			declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|  
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON)=> 
			{if (statementTrace>=1) 
				printf("\%d external_declaration Templated function declaration\n",LT(1)->line);
			}
			declaration
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			{if (statementTrace>=1) 
				printf("\%d external_declaration Templated function definition\n",LT(1)->line);
			}
			function_definition
		|
			// Templated constructor definition
            		// JEL 4/3/96 Added predicate that works once the
            		// restriction is added that ctor cannot be virtual
			(	ctor_decl_spec 
				{qualifiedItemIsOneOf(qiCtor,0)}?
			)=>
			{if (statementTrace>=1) 
				printf("\%d external_declaration Templated constructor definition\n",LT(1)->line);
			}
			ctor_definition
		)
		{endTemplateDeclaration();}
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		('enum' (ID)? LCURLY)=>
		{if (statementTrace>=1) 
			printf("\%d external_declaration Enum definition\n",LT(1)->line);
		}
		enum_specifier (init_declarator_list)? SEMICOLON {end_of_stmt();}
	|
		// Destructor definition (templated or non-templated)
		((template_head)? dtor_head[1] LCURLY)=>
		{if (statementTrace>=1) 
			printf("\%d external_declaration Destructor definition\n",LT(1)->line);
		}
		(template_head)? dtor_head[1] dtor_body
	|  
		// Constructor definition (non-templated)
		// JEL 4/3/96 Added predicate that works, once the
		// restriction is added that ctor cannot be virtual
		// and ctor_declarator uses a more restrictive id
		(	(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
			 ctor_decl_spec)?
			{qualifiedItemIsOneOf(qiCtor,0)}?
		)=>
		{if (statementTrace>=1) 
			printf("\%d external_declaration Constructor definition\n",LT(1)->line);
		}
		ctor_definition
	|  
		// User-defined type cast
		(('inline')? scope_override[$external_declaration::pScopeOverrideBuf]  conversion_function_decl_or_def)=>
		{if (statementTrace>=1) 
			printf("\%d external_declaration Operator function\n",LT(1)->line);
		}
		('inline')? s1 = scope_override[bufScopeOverrideScope] conversion_function_decl_or_def 
	|   
		// Function declaration
		(declaration_specifiers function_declarator[0] SEMICOLON)=> 
		{if (statementTrace>=1) 
			printf("\%d external_declaration Function declaration\n",LT(1)->line);
		}
		declaration_specifiers function_declarator[0] SEMICOLON {end_of_stmt();}
	|
		// Function definition
		(declaration_specifiers	function_declarator[1] LCURLY)=> 
		{if (statementTrace>=1) 
			printf("\%d external_declaration Function definition\n",LT(1)->line);
		}
		function_definition
	|
		// Function definition with int return assumed
		(function_declarator[1] LCURLY)=> 
		{if (statementTrace>=1) 
			printf("\%d external_declaration Function definition without return type\n",LT(1)->line);
		}
		function_definition
	|
		// K & R Function definition
		(declaration_specifiers	function_declarator[1] declaration)=>
		{K_and_R = TRUE;
		 if (statementTrace>=1) 
			printf("\%d external_declaration K & R function definition\n",LT(1)->line);
		}
		function_definition
	|
		// K & R Function definition with int return assumed
		(function_declarator[1] declaration)=>
		{K_and_R = TRUE;
		 if (statementTrace>=1) 
			printf("\%d external_declaration K & R function definition without return type\n",LT(1)->line);
		}
		function_definition
	|
		// Class declaration or definition
		(('extern')? (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("\%d external_declaration Class decl or def\n",LT(1)->line);
		}
		('extern')? (fs = function_specifier)* class_decl_or_def[bufScopeOverrideScope, fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}


	// by the V3-Author, concepts, copied from the above class def/decl
	//|
		// Concept declaration or definition
		//('concept' ID LCURLY)=>
		//{if (statementTrace>=1) 
		//	fprintf(stderr,"\%d external_declaration Concept decl or def\n\t begining at pos \%d\n",LT(1)->line, LT(1)->charPosition+1);
		// }
		//concept_decl_or_def 
		//{
		//	if (statementTrace>=1) 
		//	fprintf(stderr,"\t ending in line \%d at pos \%d\n",LT(1)->line, LT(1)->charPosition+1);
		 //}

		//	SEMICOLON 
		//	{
		//	end_of_stmt();}


	|
		// Copied from member_declaration 31/05/07
		(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("\%d external_declaration Declaration\n",LT(1)->line);
		}
		declaration

	|  
		// Namespace definition
		{if (statementTrace>=1) 
			printf("\%d external_declaration Namespace definition\n",LT(1)->line);
		}
		'namespace' namespace_definition
	|	
		// Semicolon
		{if (statementTrace>=1) 
			printf("\%d external_declaration Semicolon\n",LT(1)->line);
		}
		SEMICOLON {end_of_stmt();}
	|	
		// Anything else 
		{if (statementTrace>=1) 
			printf("\%d external_declaration Other Declaration\n",LT(1)->line);
		}
		declaration

	|	
		// The next two entries may be used for debugging
		// Use this statement in the source code to turn antlr trace on (See note above)
		'antlrTrace_on' {antlrTrace(TRUE);}
	|
		// Use this statement in the source code to turn antlr trace off (See note above)
		'antlrTrace_off' {antlrTrace(FALSE);}

	)
	;

//member_declaration
member_declaration
	@declarations {
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	//options{backtrack=true;}
	@init {
		lineNo = LT(1)->line;
		//FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	}
	:
	(
		// Template explicit specialisation
		('template' LESSTHAN GREATERTHAN)=>
		{if(statementTrace>=1) 
			printf("\%d member_declaration Template explicit-specialisation\n",LT(1)->line);
		}
		'template' LESSTHAN GREATERTHAN member_declaration
	|
	
		// All typedefs
	//(options{backtrack=true;}:
	 // (
		('typedef')=>
		(
			('typedef' 'enum')=>
			{if(statementTrace>=1) 
				printf("\%d member_declaration Typedef enum type\n",LT(1)->line);
			}
			'typedef' enum_specifier {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|
			(declaration_specifiers function_declarator[0] SEMICOLON)=>	// DW 11/02/05 This may not be possible member declaration
			{if(statementTrace>=1) 
				printf("\%d member_declaration Typedef function type\n",LT(1)->line);
			}
			declaration
			//SEMICOLON
		|
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if(statementTrace>=1) 
				printf("\%d member_declaration Typedef variable type\n",LT(1)->line);
			}
			declaration
			//SEMICOLON
		|
			('typedef' class_specifier)=>
			{if(statementTrace>=1) 
				printf("\%d member_declaration Typedef class type\n",LT(1)->line);
			}
			'typedef' class_decl_or_def[bufQualifiedIdScope, fs] {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
		)
	 //)
	//)
	|  
		// Templated class declaration or definition
		(template_head (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Templated class decl or def\n",LT(1)->line);
		}
		template_head (fs = function_specifier)* class_decl_or_def[bufQualifiedIdScope, fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}	// declaration
	|  
		// Templated functions and constructors matched here.
		{beginTemplateDeclaration();}
		template_head
		(  
			// templated forward class decl, init/decl of static member in template
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if (statementTrace>=1) 
				printf("\%d member_declaration Templated forward declaration\n",LT(1)->line);
				// DW 15/11/10 The above line amd other 6 were changed from antlr2. Insertion of backslash and replace getLine() with line
			}
			declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
		|
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON)=>
			{if (statementTrace>=1) 
				printf("\%d member_declaration Templated function declaration\n",LT(1)->line);
			}
			declaration
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			{if (statementTrace>=1) 
				printf("\%d member_declaration Templated function definition\n",LT(1)->line);
			}
			function_definition
		|
			// Templated constructor declarator
			(	ctor_decl_spec
				{qualifiedItemIsOneOf(qiCtor,0)}?	// DW 15/11/10 Second argument - lookahead offset - inserted
				ctor_declarator[0] SEMICOLON
			)=>
			{if (statementTrace>=1) 
				printf("\%d member_declaration Templated constructor declarator\n",LT(1)->line);
			}
			ctor_decl_spec ctor_declarator[0] SEMICOLON {end_of_stmt();}
		|
			// Templated constructor definition
			// JEL 4/3/96 Added predicate that works once the
			// restriction is added that ctor cannot be virtual
			(ctor_decl_spec {qualifiedItemIsOneOf(qiCtor,0)}?	// DW 15/11/10 Second argument - lookahead offset - inserted
			)=>
			{if (statementTrace>=1) 
				printf("\%d member_declaration Templated constructor definition\n",LT(1)->line);
			}
			ctor_definition
		|
			// Templated operator function
			{if (statementTrace>=1) 
				printf("\%d member_declaration Templated operator function\n",LT(1)->line);
			}
			conversion_function_decl_or_def
		|
			// Templated class definition
			{if (statementTrace>=1) 
				printf("\%d member_declaration Templated class definition\n",LT(1)->line);
			}
			class_head declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
		)
		{endTemplateDeclaration();}
	|
		// Enum definition (don't want to backtrack over this in other alts)
		('enum' (ID)? LCURLY)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Enum definition\n",LT(1)->line);
		}
		enum_specifier (init_declarator_list)? SEMICOLON	{end_of_stmt();}
	|
		// Constructor declarator
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor,0)}? 
			ctor_declarator[0] SEMICOLON
		)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Constructor declarator\n",LT(1)->line);
		}
		ctor_decl_spec ctor_declarator[0] SEMICOLON {end_of_stmt();}
	|  
		// JEL Predicate to distinguish ctor from function
		// This works now that ctor cannot have VIRTUAL
		// It unfortunately matches A::A where A is not enclosing
		// class -- this will have to be checked semantically
		// Constructor definition
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor,0)}?
			ctor_declarator[1]
			(COLON        // DEFINITION :ctor_initializer
			|LCURLY       // DEFINITION (compound Statement) ?
			)
		)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Constructor definition\n",LT(1)->line);
		}
		ctor_definition 
	|  
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		// Destructor declaration
		(dtor_head[0] SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Destructor declaration\n",LT(1)->line);
		}
		dtor_head[0] SEMICOLON {end_of_stmt();}
	|//
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		// Destructor definition
		(dtor_head[1] LCURLY)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Destructor definition\n",LT(1)->line);
		}
		dtor_head[1] dtor_body

	|
		// Function declaration
		(declaration_specifiers	function_declarator[0] SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Function declaration\n",LT(1)->line);
		}
		declaration_specifiers function_declarator[0] SEMICOLON {end_of_stmt();}
	
	|  
		// Function definition
		(declaration_specifiers function_declarator[1] LCURLY)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Function definition\n",LT(1)->line);
		}
		function_definition
	////	
	|
		// Class declaration or definition
		(('friend')? (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Class decl or def\n",LT(1)->line);
		}
		('friend')? (fs = function_specifier)* class_decl_or_def[bufQualifiedIdScope, fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}
	| 
		(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Declaration\n",LT(1)->line);
		}
		declaration //HERE//
	|
		// Member without a type (I guess it can only be a function declaration or definition)
		((fs = function_specifier)* function_declarator[0] SEMICOLON)=>
		{fprintf(stderr,"\%d warning Function declaration found without return type\n",LT(1)->line);
		 if (statementTrace>=1) 
			printf("\%d member_declaration Function declaration\n",LT(1)->line);
		}
		(fs = function_specifier)* function_declarator[0] SEMICOLON {end_of_stmt();}
	|
		// Member without a type (I guess it can only be a function definition)
		((fs = function_specifier)* function_declarator[1] LCURLY)=>
		{fprintf(stderr,"\%d warning Function definition found without return type\n",LT(1)->line);
		 if (statementTrace>=1) 
			printf("\%d member_declaration Function definition without return type\n",LT(1)->line);
		}
		(fs = function_specifier)* function_declarator[1] compound_statement {endFunctionDefinition();}
	|
		// User-defined type cast
		(('inline')? conversion_function_decl_or_def)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Operator function\n",LT(1)->line);
		}
		('inline')? conversion_function_decl_or_def
	|  
		// Hack to handle decls like "superclass::member",
		// to redefine access to private base class public members
		// Qualified identifier
		(qualified_id[NULL] SEMICOLON)=>
		{if (statementTrace>=1) 
			printf("\%d member_declaration Qualified ID\n",LT(1)->line);
		}
		q2 = qualified_id[bufQualifiedIdScope] SEMICOLON {end_of_stmt();}
	////	
	|
		// Access specifier  
		{if (statementTrace>=1) 
			printf("\%d member_declaration Access specifier\n",LT(1)->line);
		}
		access_specifier COLON
	|
		// Semicolon
		{if (statementTrace>=1) 
			printf("\%d member_declaration Semicolon\n",LT(1)->line);
		}
		SEMICOLON {end_of_stmt();}
	|	
		// The next two entries may be used for debugging
		// Use this statement in the source code to turn antlr trace on (See note above)
		'antlrTrace_on' {antlrTrace(TRUE);}
	|
		// Use this statement in the source code to turn antlr trace off (See note above)
		'antlrTrace_off' {antlrTrace(FALSE);}
	)
	;
	
 

//namespace_definition
namespace_definition
	:
		(ns=ID{declaratorID(($ns.text->chars),qiType);})?
		LCURLY 
		{enterNewLocalScope();}
		(external_declaration)*
		{exitLocalScope();}
		RCURLY
	;

//namespace_alias_definition
namespace_alias_definition
	@declarations {
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:
		'namespace'
		ns2=ID {declaratorID($ns2.text->chars,qiType);}
		ASSIGNEQUAL qid2 = qualified_id[bufQualifiedIdScope] SEMICOLON {end_of_stmt();} 
	;

//function_definition
function_definition
	@init {
		lineNo = LT(1)->line;
	}
	:
	(	// Next line is equivalent to guarded predicate in PCCTS
		// (SCOPE | ID)? => <<qualifiedItemIsOneOf(qiType|qiCtor)>>?
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}? 
		declaration_specifiers function_declarator[1]
		(	//{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = FALSE;}:
			(declaration)=> 
			({lineNo = LT(1)->line;} declaration)*	// Possible for K & R definition
			{in_parameter_list = FALSE;}
		)?
		compound_statement
	|	
		function_declarator[1]
		(	//{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = FALSE;}:
			(declaration)=>
			({lineNo = LT(1)->line;} declaration)*	// Possible for K & R definition
			{in_parameter_list = FALSE;}
		)?
		compound_statement
	)
	{endFunctionDefinition();}
	;

//declaration
declaration
	:	
		('extern' StringLiteral)=>
		linkage_specification
	|	
		simple_declaration
	|	
		using_statement
	;


//linkage_specification
linkage_specification
	:	
		'extern'
		StringLiteral
		(LCURLY (external_declaration)* RCURLY
		|declaration
		)
	;

//class_head
class_head
	:	// Used only by predicates
		('struct'
		|'union' 
		|'class' 
		)
		(ID	
			(LESSTHAN template_argument_list GREATERTHAN)?
			(base_clause)? 
		)? 
		LCURLY
	;

//declaration_specifiers
declaration_specifiers
    @declarations {
		StorageClass sc = scInvalid;	// auto,register,static,extern,mutable
		TypeQualifier tq = tqInvalid;	// const,volatile	// aka cv_qualifier See type_qualifier
		TypeSpecifier ts = tsInvalid;	// char,int,double, etc., class,struct,union
		FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
    }
	@init {
		// Locals
		boolean td = FALSE;	// For typedef
		boolean fd = FALSE;	// For friend

		// Global flags to allow for nested declarations
		_td = FALSE;		// For typedef
		_fd = FALSE;		// For friend
		_sc = scInvalid;	// For StorageClass		// auto,register,static,extern,mutable
		_tq = tqInvalid;	// For TypeQualifier	// aka cv_qualifier See type_qualifier
		_ts = tsInvalid;	// For TypeSpecifier
		_fs = fsInvalid;	// For FunctionSpecifier	// inline,virtual,explicit
	}
	:
	(	
		(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
			'typedef'	{td=TRUE;}			
		|	'friend'	{fd=TRUE;}
		|	sc1 = storage_class_specifier {sc = $sc1.scReturn;}	// auto,register,static,extern,mutable
		|	tq1 = type_qualifier          {tq = $tq1.tqReturn;}	// const,volatile	// aka cv_qualifier See type_qualifier
		|	fs1 = function_specifier      {fs = $fs1.fsReturn;}	// inline,virtual,explicit
		|	('_declspec'|'__declspec') LPAREN ID RPAREN 
		)* 
		ts1 = type_specifier    {ts = $ts1.tsReturn;}
		(tq1 = type_qualifier	{tq = $tq1.tqReturn;})*	// const,volatile	// aka cv_qualifier See type_qualifier
	)
	{_td=td; declarationSpecifier(td,fd,sc,tq,ts,fs);}
	;


//storage_class_specifier
storage_class_specifier returns [StorageClass scReturn]
    @init {
		$scReturn = scInvalid; 
    }
	:	'auto'		{$scReturn = scAUTO;}
	|	'register'	{$scReturn = scREGISTER;}
	|	'static'	{$scReturn = scSTATIC;}
	|	'extern'	{$scReturn = scEXTERN;}
	|	'mutable'	{$scReturn = scMUTABLE;}
	;


//function_specifier
function_specifier returns [FunctionSpecifier fsReturn]
	@init {
		$fsReturn = fsInvalid; 
	}
	:	('inline'|'_inline'|'__inline')	{$fsReturn = fsINLINE;}
	|	'virtual'						{$fsReturn = fsVIRTUAL;}
	|	'explicit'						{$fsReturn = fsEXPLICIT;}
	;

//type_specifier
type_specifier returns [TypeSpecifier tsReturn]
	@init {
		TypeQualifier tq = tqInvalid;
		$tsReturn = tsInvalid;
	}
	:	
		ts = simple_type_specifier {$tsReturn = $ts.tsReturn ;}
	;




/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////


//simple_type_specifier
simple_type_specifier returns [TypeSpecifier tsReturn]
	@declarations {
		char bufQualifiedType[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		$tsReturn = tsInvalid; 
	}
	:	//(options{backtrack=true;}:
		(
			{qualifiedItemIsOneOf(qiType|qiCtor,0)}?
			 s = qualified_type[bufQualifiedType]
		|
		//lbl_ts changed by V3-Author
			('typename'|'enum'| lbl_ts = class_specifier {$tsReturn=lbl_ts;}) 
			 s = qualified_type[bufQualifiedType]
			{declaratorID(bufQualifiedType,qiType);}	// This stores typename name in dictionary
		|	
			(	'char'		{$tsReturn |= tsCHAR;}
			|	'wchar_t'	{$tsReturn |= tsWCHAR_T;}
			|	'bool'		{$tsReturn |= tsBOOL;}
			|	'short'		{$tsReturn |= tsSHORT;}
			|	'int'		{$tsReturn |= tsINT;}
			|	('_int8'|'__int8')		{$tsReturn |= tsINT;}
			|	('_int16'|'__int16')	{$tsReturn |= tsINT;}
			|	('_int32'|'__int32')	{$tsReturn |= tsLONG;}
			|	('_int64'|'__int64')	{$tsReturn |= tsLONG;}
			|	('_w64'|'__w64')		{$tsReturn |= tsLONG;}
			|	'long'		{$tsReturn |= tsLONG;}
			|	'signed'	{$tsReturn |= tsSIGNED;}
			|	'unsigned'	{$tsReturn |= tsUNSIGNED;}
			|	'float'		{$tsReturn |= tsFLOAT;}
			|	'double'	{$tsReturn |= tsDOUBLE;}
			|	'void'		{$tsReturn |= tsVOID;}
			)+
		)
		//)
	;

//qualified_type
qualified_type [char *pQualifiedTypeBuf] returns [char *qtReturn]
	@declarations {
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		//char* so = NULL;	// DW 10/11/10 I found this commented out - //char* so = NULL;
		$qtReturn = pQualifiedTypeBuf; 
	}
	: 
		// JEL 3/29/96 removed this predicate and moved it upwards to
		// simple_type_specifier.  This was done to allow parsing of ~ID to 
		// be a unary_expression, which was never reached with this 
		// predicate on
		// {qualifiedItemIsOneOf(qiType|qiCtor,0)}?

		so = scope_override[bufScopeOverrideScope] 
//		%so=scope_override	// DW 11/11/10 Tried $so instead of original so
		{
		 strcpy(pQualifiedTypeBuf, reinterpret_cast<const char*>($so.soReturn));
		}
		id=ID 
		{
		 strcat(pQualifiedTypeBuf, reinterpret_cast<const char*>($id.text->chars));
		 $qtReturn = pQualifiedTypeBuf;
		}
		(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
		 //{(LA(1)==LESSTHAN)}? LESSTHAN template_argument_list GREATERTHAN ///*/warning(200): Decision can match input such as "LESSTHAN" using multiple alternatives: 1, 2
		 LESSTHAN template_argument_list GREATERTHAN
		)?
	;

//class_specifier
class_specifier returns [TypeSpecifier ts]
	@init {
		ts = tsInvalid;
	}
	:	
		('class'	{ts = tsCLASS;}	
		|'struct'	{ts = tsSTRUCT;}
		|'union'	{ts = tsUNION;}
		)
	;

//type_qualifier
type_qualifier returns [TypeQualifier tqReturn] // aka cv_qualifier
	@init {
		$tqReturn = tqInvalid; 
	}
	:  
		('const'	{$tqReturn = tqCONST;} 
		|'volatile'	{$tqReturn = tqVOLATILE;}
		)
	;


//class_decl_or_def
class_decl_or_def [char *pClassDeclOrDefBuf, FunctionSpecifier fs] 
	@declarations {
		TypeSpecifier ts = tsInvalid;	// Available for use
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		char *saveClass; 
	}
	:	
		('class'	{ts = tsCLASS;}	
		|'struct'	{ts = tsSTRUCT;}
		|'union'	{ts = tsUNION;}
		)
		(('_declspec'|'__declspec') LPAREN expression RPAREN)*	// Temp for Evgeniy
		(	id = qualified_id[bufQualifiedIdScope]
			{strcpy(pClassDeclOrDefBuf, reinterpret_cast<const char*>($id.text->chars));}
			(//{dummyVar}? //added by V3-Author //options{generateAmbigWarnings = false;}:
				(SEMICOLON|member_declarator)=>
				// Empty 
				{classForwardDeclaration(pClassDeclOrDefBuf, ts, fs);}	// This stores class name in dictionary
			|
				(base_clause)?
				LCURLY
				{saveClass = enclosingClass; enclosingClass = bufQualifiedIdScope; 
				 beginClassDefinition(pClassDeclOrDefBuf, ts);}	// This stores class name in dictionary
				(member_declaration)*
				{endClassDefinition();}
				RCURLY
				{enclosingClass = saveClass;}
			)
		|
			LCURLY
			{saveClass = enclosingClass; enclosingClass = "__anonymous";
			 beginClassDefinition("anonymous", ts);}	// This stores "anonymous" name in dictionary
			(member_declaration)*
			{endClassDefinition();}
			RCURLY
			{enclosingClass = saveClass;}
		)
	;

//base_clause
base_clause
	:	
		COLON base_specifier (COMMA base_specifier)*
	;

//base_specifier
base_specifier
	@declarations {
	    char *qt = NULL; //FIXME: what it is used for?
		char bufQualifiedType[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:	
		(	'virtual' (access_specifier)? qt1 = qualified_type[bufQualifiedType] {qt = $qt1.qtReturn;}
		|	access_specifier ('virtual')? qt2 = qualified_type[bufQualifiedType] {qt = $qt2.qtReturn;}
		|	qt3 = qualified_type[bufQualifiedType]  {qt = $qt3.qtReturn;}
		)
	;

//access_specifier
access_specifier
	:	
		(	'public'
		|	'protected'
		|	'private'
		)
	;

//enum_specifier
enum_specifier
	@declarations {
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:	
		'enum'
		(	
			LCURLY enumerator_list RCURLY
		|	
			id1 = qualified_id[bufQualifiedIdScope]
			{beginEnumDefinition((char*)$id1.text->chars);}	// This stores id name as an enum type in dictionary
			(LCURLY enumerator_list RCURLY)?
			{endEnumDefinition();}
		)
	;

//enumerator_list
enumerator_list
	:	
		enumerator (COMMA (enumerator)? )*	// Allows comma at end of list
	;

//enumerator
enumerator
	:	
		id=ID (ASSIGNEQUAL constant_expression)?
		{enumElement((char*)($id.text->chars));}	// This stores id name in dictionary
	;




// This matches a generic qualified identifier ::T::B::foo
 // (including OPERATOR).
 // It might be a good idea to put T::~dtor in here
 // as well, but id_expression in expr.g puts it in manually.
 // Maybe not, 'cause many people use this assuming only A::B.
 // How about a 'qualified_complex_id'?
//
//qualified_id
qualified_id [char *pScopeReturnBuf] returns [char *qiReturn]
	@declarations {
		char bufOptorScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		$qiReturn = pScopeReturnBuf; 
	}
	:	
		so =  scope_override[bufScopeOverrideScope]
		{ 
		strcpy(pScopeReturnBuf, reinterpret_cast<const char*>($so.soReturn));
		} 
		(	id=ID {strcat(pScopeReturnBuf, reinterpret_cast<const char*>($id.text->chars));}
			((LESSTHAN template_argument_list GREATERTHAN)=>
			  LESSTHAN template_argument_list GREATERTHAN)? // {strcat(pScopeReturnBuf,"<...>");}
		|  
			OPERATOR op1=optor[bufOptorScope]
			{strcat(pScopeReturnBuf,"operator"); strcat(pScopeReturnBuf, reinterpret_cast<const char*>($op1.oReturn));}
		|
			TILDE id_expression		// 1/08/07
		)
		{
		$qiReturn = pScopeReturnBuf;
		}
	;

//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////


//typeID
typeID
	:	
		{isTypeName((char*)LT(1)->getText(LT(1))->chars)}?
		ID
	;

//init_declarator_list
init_declarator_list
	:	
		member_declarator (COMMA member_declarator)*
	;

//member_declarator
member_declarator
	:	
		((ID)? COLON constant_expression)=>(ID)? COLON constant_expression
	|  
		declarator
		(
			(ASSIGNEQUAL OCTALINT SEMICOLON)=> ASSIGNEQUAL OCTALINT	// The value must be zero (for pure virtual)
		|	
			ASSIGNEQUAL 
			initializer
		|	
			LPAREN expression_list RPAREN // member function / method declaration
		)?
	;

//initializer
initializer
	:	
		remainder_expression	// assignment_expression
	|	
		LCURLY initializer (COMMA (initializer)? )* RCURLY	// Allows comma at end of list
	;

//declarator
declarator
	:
		(ptr_operator)=> ptr_operator	// AMPERSAND or STAR etc.
		declarator
	|	
		direct_declarator
	;

//direct_declarator
direct_declarator
	scope { 
		char *pQualifiedIdBuf; 
	}
	@declarations {
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		$direct_declarator::pQualifiedIdBuf = bufQualifiedIdScope; 
	}
	:	
		(qualified_id[$direct_declarator::pQualifiedIdBuf] LPAREN (RPAREN|declaration_specifiers) )=>	// Must be function declaration
		id1 = qualified_id[bufQualifiedIdScope]
		{if (_td==TRUE)       // This statement is a typedef   
			declaratorID($id1.qiReturn,qiType);
		 else
			declaratorID($id1.qiReturn,qiFun);
		}
		LPAREN {declaratorParameterList(0);}
		(parameter_list)?
		RPAREN {declaratorEndParameterList(0);}
		(tq = type_qualifier)*
		(exception_specification)?
	|	
		(qualified_id[$direct_declarator::pQualifiedIdBuf] LPAREN qualified_id[$direct_declarator::pQualifiedIdBuf])=>	// Must be class instantiation
		id2 = qualified_id[bufQualifiedIdScope]
		{declaratorID($id2.qiReturn,qiVar);}
		LPAREN
		expression_list
		RPAREN
	|
		(qualified_id[$direct_declarator::pQualifiedIdBuf] LSQUARE)=>	// Must be array declaration
		id3 = qualified_id[bufQualifiedIdScope]
		{//printf("02\n");
		if (_td==TRUE)       // This statement is a typedef   
			declaratorID($id3.qiReturn,qiType);	// This statement is a typedef
		 else 
			declaratorID($id3.qiReturn,qiVar);
		 is_address = FALSE; is_pointer = FALSE;
		}
		(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
		 LSQUARE (constant_expression)? RSQUARE)+
		{declaratorArray();}
	|
		(qualified_id[$direct_declarator::pQualifiedIdBuf] RPAREN LPAREN)=>	// Must be function declaration (see function_direct_declarator)
		id4 = qualified_id[bufQualifiedIdScope]
		{
		if (_td==TRUE)       // This statement is a typedef   
			declaratorID($id4.qiReturn,qiType);	// This statement is a typedef
		 else
			declaratorID($id4.qiReturn,qiFun);
		 is_address = FALSE; is_pointer = FALSE;
		}
	|
		id5 = qualified_id[bufQualifiedIdScope]
		{
		if (_td==TRUE)
			{
			declaratorID($id5.qiReturn,qiType);	// This statement is a typedef
			}
		 else
			declaratorID($id5.qiReturn,qiVar);
		 is_address = FALSE; is_pointer = FALSE;
		}
	|	
		LPAREN declarator RPAREN 
		(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
		 declarator_suffix)? // DW 1/9/04 declarator_suffix made optional as failed on line 2956 in metrics.i
	;					// According to the grammar a declarator_suffix is not required here

//declarator_suffix
declarator_suffix		// Note: Only used above in direct_declarator
	//{CPPParser::TypeQualifier tq;}  
	:
	(	
		//(options {warnWhenFollowAmbig = false;}:
		(LSQUARE (constant_expression)? RSQUARE)+
		{declaratorArray();}
	|	
		{(!((LA(1)==LPAREN)&&(LA(2)==ID))||(qualifiedItemIsOneOf(qiType|qiCtor,1)))}?
		LPAREN {declaratorParameterList(0);}
		(parameter_list)?
				RPAREN {declaratorEndParameterList(0);}
		(tq = type_qualifier)*
		(exception_specification)?
	)
	;



//conversion_function_decl_or_def
conversion_function_decl_or_def
	:
		OPERATOR declaration_specifiers (STAR | AMPERSAND)?	// DW 01/08/03 Use type_specifier here? see syntax
		( LESSTHAN template_parameter_list GREATERTHAN /*{wasInTemplate=FALSE;}*/ )?
		LPAREN (parameter_list)? RPAREN
		(tq = type_qualifier)*	// DW 29/07/05 ? changed to *
		(exception_specification)?
		(	compound_statement
		|	SEMICOLON {end_of_stmt();}
		)
	;

 //function_declarator
function_declarator [int definition]
	:	
		(ptr_operator)=> ptr_operator function_declarator[definition]
	|	
		function_direct_declarator[definition]
	;

//function_direct_declarator
function_direct_declarator [int definition] 
	@declarations {
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:
		(	// fix prompted by (isdigit)() in xlocnum
			LPAREN 
			declarator
			RPAREN
		|
			q1 = qualified_id[bufQualifiedIdScope]
			{
			declaratorID($q1.qiReturn,qiFun);
			}
		)

		{		
		#ifdef MYCODE
		if (definition)
			myCode_function_direct_declarator(q);
		#endif MYCODE
		}

		LPAREN 
		{
		functionParameterList();
		if (K_and_R == TRUE)
			in_parameter_list = FALSE;
		else
			in_parameter_list = TRUE;
		}
		(parameter_list)? 
		{
		if (K_and_R == TRUE)
	  		in_parameter_list = TRUE;
		else
			in_parameter_list = FALSE;
		}
		RPAREN
		(//{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
		 tq = type_qualifier)*
		(ASSIGNEQUAL OCTALINT)?	// The value of the octal must be 0
		{functionEndParameterList(definition);}
		(exception_specification)?
	;






/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

//ctor_definition
ctor_definition 
	:
		ctor_head
		ctor_body
		{endConstructorDefinition();}
	;

//ctor_head
ctor_head 
	:
		ctor_decl_spec
		ctor_declarator[1]
	;

//ctor_decl_spec
ctor_decl_spec
	:
		(('inline'|'_inline'|'__inline')|'explicit')*
	;

//ctor_declarator
ctor_declarator[int definition]
	@declarations {
		char bufQualifiedCtorIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	: 
		q1 = qualified_ctor_id[bufQualifiedCtorIdScope]
		{declaratorParameterList(definition);}
		LPAREN (parameter_list)? RPAREN
		{declaratorEndParameterList(definition);}
		(exception_specification)?
	;


// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_id [char *pQualifiedCtorIdBuf] returns [char *qcReturn]
	@declarations {
		char *so = NULL;
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		//if (pQualifiedCtorIdBuf) *pQualifiedCtorIdBuf = '\0';
		$qcReturn = pQualifiedCtorIdBuf; 
	}
	: 
		so1 = scope_override[bufScopeOverrideScope]
		{strcpy(pQualifiedCtorIdBuf, reinterpret_cast<const char*>($so1.soReturn));}
		id=ID	// DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
		{strcat(pQualifiedCtorIdBuf, reinterpret_cast<const char*>($id.text->chars));
		$qcReturn = pQualifiedCtorIdBuf;
		//printf("CPP_parser.g qualified_ctor_id q \%s\n",$qcReturn);
		} 
	;

//ctor_body
ctor_body
	:
		(ctor_initializer)?
		compound_statement
	;

//ctor_initializer
ctor_initializer
	:
		COLON superclass_init (COMMA superclass_init)*
	;

//superclass_init
superclass_init
	@declarations {
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	} 
	: 
		q1 = qualified_id[bufQualifiedIdScope] LPAREN (expression_list)? RPAREN
	;

//dtor_head
dtor_head[int definition]
	:
		dtor_decl_spec
		dtor_declarator[definition]
	;

//dtor_decl_spec
dtor_decl_spec
	:
		(('inline'|'_inline'|'__inline'|'virtual')*)
	;

//dtor_declarator
dtor_declarator[int definition]
	@declarations {
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	} 
	:	
		s1 = scope_override[bufScopeOverrideScope]
		TILDE ID
		{declaratorParameterList(definition);}
		LPAREN ('void')? RPAREN
		{declaratorEndParameterList(definition);}
		(exception_specification)?
	;

//dtor_body
dtor_body
	:
		compound_statement
		{endDestructorDefinition();}
	;

//parameter_list
parameter_list
	:	
		parameter_declaration_list (ELLIPSIS)?
	;

//parameter_declaration_list
parameter_declaration_list
	:	
		(parameter_declaration (COMMA parameter_declaration)* )
	;

//parameter_declaration	(See also template_parameter_declaration) 
parameter_declaration
	:	
		{beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
			 (!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}?
			
			declaration_specifiers	// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> declarator        // if arg name given
			| 
				abstract_declarator     // if arg name not given  // can be empty
			)
		|
					(declarator)=> declarator			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS
		)
		(ASSIGNEQUAL 
		 remainder_expression // DW 18/4/01 assignment_expression
		)?
	;

//type_id
type_id
	:
		declaration_specifiers abstract_declarator
	;

// This rule looks a bit weird because (...) can happen in two
// places within the declaration such as "void (*)()" (ptr to
// function returning nothing).  However, the () of a function
// can only occur after having seen either a (abstract_declarator)
// and not after a [..] or simple '*'.  These are the only two
// valid () func-groups:
//    int (*)();     // ptr to func
//    int (*[])();   // array of ptr to func
 //
//abstract_declarator
abstract_declarator
	:	
		ptr_operator abstract_declarator 
	|	
		(LPAREN abstract_declarator RPAREN (LSQUARE|LPAREN) )=> LPAREN abstract_declarator RPAREN
		(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
		abstract_declarator_suffix)
	|	
		(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
		abstract_declarator_suffix)?
	;

//abstract_declarator_suffix
abstract_declarator_suffix
	:	
		(LSQUARE (constant_expression)? RSQUARE)+
		{declaratorArray();}
	|
		LPAREN
		{declaratorParameterList(0);}
		(parameter_list)?
		RPAREN
		{declaratorEndParameterList(0);}
		cv_qualifier_seq
		(exception_specification)?
	;

//exception_specification
exception_specification
	@declarations {
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:	
		'throw'
		LPAREN 
		(	(so1 = scope_override[bufScopeOverrideScope] ID (COMMA so2 = scope_override[bufScopeOverrideScope] ID)* )? 
		|	ELLIPSIS
		)
		RPAREN
	;

//template_head
template_head
	:	
		'template'
		LESSTHAN template_parameter_list GREATERTHAN
	;

//template_parameter_list
template_parameter_list
	:	
		{ //wasInTemplate=TRUE;
		beginTemplateParameterList();}
		template_parameter (COMMA template_parameter)*
		{endTemplateParameterList();}
	;

// Rule requires >2 lookahead tokens. The ambiguity is resolved 
// correctly, however. According to the manual "...A template argument
// that can be interpreted either as a parameter-declaration or a
// type-argument (because its identifier is the name of an
// already existing class) is taken as type-argument."
// Therefore, any "class ID" that is seen on the input, should
// match the first alternative here (it should be a type-argument).
 //
//template_parameter
template_parameter
	:	
		(//{dummyVar}? //added by V3-Author //options{generateAmbigWarnings = false;}:
		 type_parameter
		|
		 (parameter_declaration)=>
		  parameter_declaration
		|
		 template_parameter_declaration
		)
	;

//type_parameter
type_parameter
	:
		(	
			('class'|'typename') 
			(id=ID
				{
				templateTypeParameter((char*)$id.text->chars);
				}
				(ASSIGNEQUAL assigned_type_name)?
			)?
		|
			template_head 'class' 
			(id2=ID
				{
				templateTypeParameter((char*)$id2.text->chars);
				}
				(ASSIGNEQUAL assigned_type_name)?
			)?
		)
	;

// This is to allow an assigned type_name in a template parameter
//	list to be defined previously in the same parameter list,
//	as type setting is ineffective whilst guessing
 //
//assigned_type_name
assigned_type_name
	@declarations {
		char* qt = NULL; 
		TypeSpecifier ts;
		char bufQualifiedType[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:
		(//{dummyVar}? //added by V3-Author //options{generateAmbigWarnings = false;}:
			qt1 = qualified_type[bufQualifiedType] abstract_declarator  {qt = $qt1.qtReturn;}
		|
			ts1 = simple_type_specifier abstract_declarator  {ts = $ts1.tsReturn;}
		)
	;

//template_parameter_declaration	(See also parameter_declaration)
template_parameter_declaration
	:	
		{beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
			 (!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}?
			
			declaration_specifiers	// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> declarator        // if arg name given
			| 
				abstract_declarator     // if arg name not given  // can be empty
			)
		|
			(declarator)=> declarator			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS
		)
		(ASSIGNEQUAL
		 additive_expression	// DW 04/09/07 because of ambiguity of ">"
		)?
	;

// This rule refers to an instance of a template class or function
//template_id
template_id	// aka template_class_name
	:	
		ID LESSTHAN template_argument_list GREATERTHAN
	;

//template_argument_list
template_argument_list
	:	
		template_argument (COMMA template_argument)*
	;

// Here assignment_expression was changed to shift_expression to rule out
//  x< 1<2 > which causes ambiguities. As a result, these can be used only
//  by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
//  x<(1+2)> ==> ok.
 //
//template_argument
template_argument
	:
		// DW 07/04/05 This predicate only used here if next is SCOPE or ID
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}?
		type_id
	|	
		shift_expression // failed in iosfwd
	;



///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

//statement_list
statement_list
	:	
		(statement)+
	;

//statement
statement
	scope { 
		char *pQualifiedIdBuf;
	}
	@declarations {
		FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		lineNo = 0;
		lineNo = LT(1)->line;
		//FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
		$statement::pQualifiedIdBuf = bufQualifiedIdScope; 
	}
	// all {dummyVar}? are added by V3-Author
	:
		(	('namespace'|'using')=>
			block_declaration
		|	(('typedef')? class_specifier (qualified_id[$statement::pQualifiedIdBuf])? LCURLY)=>
			 member_declaration
		|	(declaration_specifiers ((ptr_operator)=>ptr_operator)? qualified_id[$statement::pQualifiedIdBuf])=>
			 member_declaration
		|	 (labeled_statement)=> 
			 labeled_statement
		|	 case_statement
		|	 default_statement
		|	 expression SEMICOLON {end_of_stmt();}
		|	 compound_statement
		|	 selection_statement
		|	 iteration_statement
		|	 jump_statement
		|	 SEMICOLON {end_of_stmt();}
		|	 try_block
		|	 throw_statement
			// The next two entries may be used for debugging
			// Use this statement in the source code to turn antlr trace on (See note above)
		|	'antlrTrace_on' {antlrTrace(TRUE);}
			// Use this statement in the source code to turn antlr trace off (See note above)
		|	'antlrTrace_off' {antlrTrace(FALSE);}
		)
	
	;

//block_declaration
block_declaration
	:	simple_declaration
	|	namespace_alias_definition
	|	using_statement
	;

//simple_declaration
simple_declaration
	:
		declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
	;

//labeled_statement
labeled_statement
	:	
		ID COLON statement
	;

//case_statement
case_statement
	:	'case'
		constant_expression COLON statement
	;

//default_statement
default_statement
	:	
		'default' COLON statement
	;

//compound_statement
compound_statement
	:	
		LCURLY 
		{end_of_stmt();
		 enterNewLocalScope();
		}
		(statement_list)?
		RCURLY 
		{exitLocalScope();}
	;

// NOTE: cannot remove ELSE ambiguity, but it parses correctly.
// The warning is removed with the options statement
///
//selection_statement
selection_statement
	:	
		'if' LPAREN 
		{enterNewLocalScope();}
		condition RPAREN
		st1 = statement
		(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
		 'else' st2 = statement)?
		{exitLocalScope();}
	|	
		'switch' LPAREN
		{enterNewLocalScope();}
		condition RPAREN statement
		{exitLocalScope();}
	;

//iteration_statement
iteration_statement
	:	
		'while'	LPAREN
		{enterNewLocalScope();}
		condition RPAREN 
		statement  
		{exitLocalScope();}
	|	
		'do' 
		{enterNewLocalScope();}
		statement 'while'
		LPAREN expression RPAREN 
		{exitLocalScope();}
		SEMICOLON {end_of_stmt();} 
	|	
		'for' LPAREN
		{enterNewLocalScope();}
		(	(declaration)=> declaration 
		|	(expression)? SEMICOLON {end_of_stmt();}
		)
		(condition)? SEMICOLON {end_of_stmt();}
		(expression)?
		RPAREN statement	 
		{exitLocalScope();}
	;

//condition
condition
	:
		(	(declaration_specifiers declarator ASSIGNEQUAL)=> 
			 declaration_specifiers declarator ASSIGNEQUAL remainder_expression
		|	expression
		)
	;

//jump_statement
jump_statement
	:	
		(	'goto' ID SEMICOLON {end_of_stmt();}
		|	'continue' SEMICOLON {end_of_stmt();}
		|	'break' SEMICOLON {end_of_stmt();}
		|	// DW 16/05/03 May be problem here if return is followed by a cast expression 
			'return' {in_return = TRUE;}
			(	//{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
			                                       // THE ,0 was added by V3-Author
				(LPAREN {(qualifiedItemIsOneOf(qiType,0) )}? ID RPAREN)=> 
				LPAREN ID RPAREN (expression)?	// This is an unsatisfactory fix for problem in xstring re 'return (allocator);'
												//  and in xlocale re return (_E)(_Tolower((unsigned char)_C, &_Ctype));
				//{printf("\%d CPP_parser.g jump_statement Return fix used\n",lineNo);}
			|	expression 
			)?	SEMICOLON {in_return = FALSE; end_of_stmt();} 
		)
	;

//try_block
try_block
	:	
		'try' compound_statement (handler)*
	;

//handler
handler
	:	
		'catch'
		{exceptionBeginHandler();}
		{declaratorParameterList(1);}
		LPAREN exception_declaration RPAREN
		{declaratorEndParameterList(1);}
		compound_statement
		{exceptionEndHandler();}
	;

//exception_declaration
exception_declaration
	:	
		parameter_declaration_list
	;

// This is an expression of type void according to the ARM, which
// to me means "statement"; it removes some ambiguity to put it in
// as a statement also.
///
//throw_statement
throw_statement
	:	
		'throw' (assignment_expression) ? SEMICOLON { end_of_stmt();}
	;

//using_statement
using_statement
	@declarations {
		char *qid = NULL; //FIXME: not used
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:		
		'using'
		('namespace' qid1 = qualified_id[bufQualifiedIdScope]		// Using-directive
		|('typename')? qid2 = qualified_id[bufQualifiedIdScope]	// Using-declaration
		)
		SEMICOLON {end_of_stmt();}
	;


///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

// Same as expression_list
//expression
expression
	@init {
		lineNo = LT(1)->line;
	}
	:	
		assignment_expression (COMMA assignment_expression)*
	;

// right-to-left for assignment op
//assignment_expression
assignment_expression
	:	
		conditional_expression
		(	//options{backtrack=true; k=3;}:
			(ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MINUSEQUAL|PLUSEQUAL
			|MODEQUAL|SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL
			|BITWISEXOREQUAL|BITWISEOREQUAL
			)
			remainder_expression
		)?
	;


//remainder_expression
remainder_expression
	:
		(	
			(conditional_expression (COMMA|SEMICOLON|RPAREN) )=>
			{assign_stmt_RHS_found += 1;}
			assignment_expression
			{
			if (assign_stmt_RHS_found > 0)
				assign_stmt_RHS_found -= 1;
			else
				{
				fprintf(stderr,"\%d warning Error in assign_stmt_RHS_found = \%d\n",
					LT(1)->line,assign_stmt_RHS_found);
				fprintf(stderr,"Press return to continue\n");
				getchar();
				}
			}
		|	
			assignment_expression
		)
	;

//conditional_expression
conditional_expression
	:	
		logical_or_expression
		(QUESTIONMARK expression COLON conditional_expression)?
	;

//constant_expression
constant_expression
	:	
		conditional_expression
	;

//logical_or_expression
logical_or_expression
	:	
		logical_and_expression (OR logical_and_expression)* 
	;

//logical_and_expression
logical_and_expression
	:	
		inclusive_or_expression (AND inclusive_or_expression)* 
	;

//inclusive_or_expression
inclusive_or_expression
	:	
		exclusive_or_expression (BITWISEOR exclusive_or_expression)*
	;

//exclusive_or_expression
exclusive_or_expression
	:	
		and_expression (BITWISEXOR and_expression)*
	;

//and_expression
and_expression
	:	
		equality_expression (AMPERSAND equality_expression)*
	;

//equality_expression
equality_expression
	:	
		relational_expression ( (NOTEQUAL|EQUAL) relational_expression)*
	;

//relational_expression
relational_expression
	:	
		shift_expression
		(options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
			//{!wasInTemplate}?
			(
				(	LESSTHAN
				|	GREATERTHAN
				|	LESSTHANOREQUALTO
				|	GREATERTHANOREQUALTO
				)
			 	
		 	)shift_expression
		)?
	;

//shift_expression
shift_expression
	:	
		additive_expression ((SHIFTLEFT | SHIFTRIGHT) additive_expression)*
	;

// See comment for multiplicative_expression regarding #pragma
additive_expression
	:	
		multiplicative_expression
		(//options{backtrack=true;k=3;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
			(PLUS | MINUS) multiplicative_expression
		)*
	;

// ANTLR has trouble dealing with the analysis of the confusing unary/binary
// operators such as STAR, AMPERSAND, PLUS, etc...  
// With the #pragma (now "(options{warnWhenFollowAmbig = false;}:" etc.)
// we simply tell ANTLR to use the "quick-to-analyze" approximate lookahead
// as full LL(k) lookahead will not resolve the ambiguity anyway.  Might
// as well not bother.  This has the side-benefit that ANTLR doesn't go
// off to lunch here (take infinite time to read grammar).
multiplicative_expression
	:	
		pm_expression
		(//options{backtrack=true;k=3;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
			(STAR|DIVIDE|MOD) pm_expression
		)*
	;

//pm_expression
pm_expression
	:	
		cast_expression ( (DOTMBR|POINTERTOMBR) cast_expression)*
	;

// The string "( ID" can be either the start of a cast or
///the start of a unary_expression.  However, the ID must
// be a type name for it to be a cast.  Since ANTLR can only hoist
// semantic predicates that are visible without consuming a token,
// the semantic predicate in rule type_name is not hoisted--hence, the
// rule is reported to be ambiguous.  I am manually putting in the
// correctly hoisted predicate.
//
// Ack! Actually "( ID" might be the start of "(T(expr))" which makes
// the first parens just an ordinary expression grouping.  The solution
// is to look at what follows the type, T.  Note, this could be a
// qualified type.  Yucko.  I believe that "(T(" can only imply
// function-style type cast in an expression (...) grouping.
//
// We DO NOT handle the following situation correctly at the moment:
// Suppose you have
//    struct rusage rusage;
//    return (rusage.fp);
//    return (rusage*)p;
// Now essentially there is an ambiguity here. If rusage is followed by any
// postix operators then it is an identifier else it is a type name. This
// problem does not occur in C because, unless the tag struct is attached,
// rusage is not a type name. However in C++ that restriction is removed.
// No *real* programmer would do this, but it's in the C++ standard just for
// fun..
//
// Another fun one (from an LL standpoint):
//
//   (A::B::T *)v;      // that's a cast of v to type A::B::T
//   (A::B::foo);    // that's a simple member access
//
// The qualifiedItemIs(1) function scans ahead to what follows the
// final "::" and returns qiType if the item is a type.  The offset of
// '1' makes it ignore the initial LPAREN; normally, the offset is 0.
 //

//cast_expression
cast_expression 
	:
		(LPAREN type_id RPAREN unary_expression)=>
		 LPAREN type_id RPAREN unary_expression
	|
		// Believe it or not, you can get more than one cast expression in sequence
		(LPAREN type_id RPAREN cast_expression)=>
		 LPAREN type_id RPAREN cast_expression
	|  
		unary_expression	// handles outer (...) of "(T(expr))"
	;


//unary_expression
unary_expression
	:
		(	
			(postfix_expression)=> 
			postfix_expression
		|	
			PLUSPLUS unary_expression
		|	
			MINUSMINUS unary_expression
		|	
			unary_operator cast_expression
		|	
			('sizeof'
			|'__alignof__' 	//Zhaojz 02/02/05 to fix bug 29 (GNU)
			)
			(	(unary_expression)=>
				 unary_expression
			|
				LPAREN type_id RPAREN
			)
		|   
			(SCOPE)?
			(new_expression
			|delete_expression
			)
		)
	;


//postfix_expression
postfix_expression
	:	//options{backtrack=true;k=3;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
	//	Function-style cast must have a leading type
	//	{!(LA(1)==LPAREN)}?
	//	(ts = simple_type_specifier LPAREN RPAREN LPAREN)=>	// DW 01/08/03 To cope with problem in xtree (see test10.i) 
	//	  ts =simple_type_specifier LPAREN RPAREN LPAREN (expression_list)? RPAREN 
	//|
	//	{!(LA(1)==LPAREN)}?		// DW 09/11/10 Took out "=>" following "?"	
	//	(ts = simple_type_specifier LPAREN)=>
	//	 ts = simple_type_specifier LPAREN (expression_list)? RPAREN 
	//	// Following put in to allow for the above being a constructor as shown in test_constructors_destructors.cpp
	//	(DOT postfix_expression)?
	
// Above left factored DW 13/11/10
	//	Function-style cast must have a leading type
	//	{!(LA(1)==LPAREN)}?	// DW 13/11/10 Probably incorrect as a simple_type_specifier could consist of more than one symbol
		(ts = simple_type_specifier LPAREN)=>	// DW 22/11/10 Included to stop false entry into these two alternatives
		ts = simple_type_specifier LPAREN
		(
		RPAREN LPAREN (expression_list)? RPAREN // DW 01/08/03 To cope with problem in xtree (see test10.i)
		|
		(expression_list)? RPAREN
		// Following put in to allow for the above being a constructor as shown in test_constructors_destructors.cpp
		(DOT postfix_expression)?
		)
	|  
		primary_expression
		(//options{backtrack=true;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
        	(LSQUARE expression RSQUARE
			 |	LPAREN (expression_list)? RPAREN // function call/function-call or method call/method-call.
			 |	(DOT|POINTERTO) ('template')? id_expression
			 |	PLUSPLUS 
			 |	MINUSMINUS
			)*
		)
	|
		('dynamic_cast'|'static_cast'|'reinterpret_cast'|'const_cast')
		LESSTHAN ('const')? ts = type_specifier (ptr_operator)? GREATERTHAN
		LPAREN expression RPAREN
	|
		'typeid' 
		LPAREN ((type_id)=>type_id|expression) RPAREN
		( (DOT|POINTERTO) postfix_expression)?
	
	;

//primary_expression
primary_expression
	:	id_expression
	|	literal
	|	'this'
	|	LPAREN expression RPAREN
	;

//id_expression
id_expression 
	@declarations {
		char bufQualifiedIdScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:
		(	s1 = qualified_id[bufQualifiedIdScope] 
		)
	;


//literal
literal
	://options{backtrack=true;k=2;}:
	(	OCTALINT
	|	DECIMALINT
	|	HEXADECIMALINT
	|	CharLiteral
	|	WCharLiteral
	|	(StringLiteral|WStringLiteral)+
	|	FLOATONE
	|	FLOATTWO
	|	'true'
	|	'false')
	
	;

//unary_operator
unary_operator
	:
	//options{backtrack=true;}:	
	AMPERSAND
	|	STAR
	|	PLUS
	|	MINUS
	|	TILDE
	|	NOT
	;


// JEL The first ()? is used to resolve "new (expr) (type)" because both
// (expr) and (type) look identical until you've seen the whole thing.
//
// new_initializer appears to be conflicting with function arguments as
// function arguments can follow a primary_expression.  [This is a full
// LL(k) versus LALL(k) problem.  Enhancing context by duplication of
// some rules might handle this.]
///
//new_expression
new_expression
	:
	(  
		'new'
		(	(LPAREN expression_list RPAREN)=> 
			 LPAREN expression_list RPAREN)?
		(
		(LPAREN type_id RPAREN)=> LPAREN type_id RPAREN
		|new_type_id)
		(//{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:	
		(new_initializer)=> new_initializer)?
	)
	;

//new_initializer
new_initializer
	:	
		LPAREN (expression_list)? RPAREN
	;

//new_type_id
new_type_id
	:	
		declaration_specifiers 
		(//options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
			new_declarator
		)?
	;

//new_declarator
new_declarator
	:	 
		ptr_operator
		(//options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
		new_declarator)?
	|	
		direct_new_declarator
	;

// The "[expression]" construct conflicts with the "new []" construct
// (and possibly others).  We used approximate lookahead for the "new []"
// construct so that it would not try to compute full LL(2) lookahead.
// Here, we use #pragma approx again because anytime we see a [ followed
// by token that can begin an expression, we always want to loop.
// Approximate lookahead handles this correctly.  In fact, approximate
// lookahead is the same as full lookahead when all but the last lookahead
// depth are singleton sets; e.g., {"["} followed by FIRST(expression).
///
//direct_new_declarator
direct_new_declarator
	:
		(//options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
			(LSQUARE expression RSQUARE)
		)+
	;


//ptr_operator
ptr_operator 
	scope { 
		char *pScopeOverrideBuf; 
	}
	@declarations {
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	@init {
		$ptr_operator::pScopeOverrideBuf = bufScopeOverrideScope; 
	}
	:	//options{backtrack=true;}:
			 AMPERSAND 	{is_address = TRUE;} |
			 ('_cdecl'|'__cdecl') 
		|	 ('_near'|'__near') 
		|	 ('_far'|'__far') 
		|	 '__interrupt' 
		|	 ('pascal'|'_pascal'|'__pascal') 
		|	 ('_stdcall'|'__stdcall') 
		|	(s1 = scope_override[$ptr_operator::pScopeOverrideBuf] STAR cv_qualifier_seq)=>
			 s2 = scope_override[bufScopeOverrideScope] STAR {is_pointer = true;} cv_qualifier_seq
		
		
			
   ;
   
  

// Match A::B::*	// May be redundant 14/06/06
//ptr_to_member
ptr_to_member	// Part of ptr_operator in grammar.txt
	@declarations {
		char bufScopeOverrideScope[CPPParser_MaxQualifiedItemSize+1] = {0}; 
	}
	:
		s1 = scope_override[bufScopeOverrideScope] STAR  {is_pointer = true;} cv_qualifier_seq
	;

// JEL note:  does not use (const|volatile)* to avoid lookahead problems
//cv_qualifier_seq
cv_qualifier_seq
	@declarations {
		TypeQualifier tq;
	}
	:
		(tq1 = type_qualifier {tq = $tq1.tqReturn;})*
	;


// Match "(::)A::B::C::(template)" or just "::"
//scope_override  // DW 28/11/10 Otherwise known as nested-name-specifier 
scope_override [char *pBufScopeOverrideBuf] returns [char *soReturn]
	@init  {
		$soReturn = pBufScopeOverrideBuf;
	}
	:
		(SCOPE {strcat(pBufScopeOverrideBuf,"::");} )? 
		(	//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
			//{dummyVar2}? //added by V3-Author 
			(ID LESSTHAN template_argument_list GREATERTHAN SCOPE)=>
			id1=ID {strcat(pBufScopeOverrideBuf, reinterpret_cast<const char*>($id1.text->chars));}
			LESSTHAN template_argument_list GREATERTHAN // {strcat(pBufScopeOverrideBuf,"<...>");} //Note: v4.1 loosing template info
			SCOPE{strcat(pBufScopeOverrideBuf,"::");} 
			('template' {strcat(pBufScopeOverrideBuf,"template");})?
			
		|	
			(ID SCOPE)=> // added by V3-Author
			//{dummyVar}? //added by V3-Author 
			id2=ID {strcat(pBufScopeOverrideBuf, reinterpret_cast<const char*>($id2.text->chars));}
			SCOPE {strcat(pBufScopeOverrideBuf,"::");}
			('template' {strcat(pBufScopeOverrideBuf,"template");})?
			
		)*
		{
		$soReturn = pBufScopeOverrideBuf;
		}
	;



//delete_expression
delete_expression
	:	
		'delete' (LSQUARE RSQUARE)? cast_expression
	;

// Same as expression
//expression_list
expression_list
	:	
		assignment_expression (COMMA assignment_expression)*
	;

//optor
optor [char *pScopeReturnBuf] returns [char* oReturn]
	@init {
		if (pScopeReturnBuf) *pScopeReturnBuf = '\0'; 
		$oReturn = pScopeReturnBuf;
		//TypeSpecifier ts=tsInvalid;
	}
	:	// NOTE: you may need to add backtracking depending on the C++ standard specifications used...
		// but for now V3-Author has decided not to add that and go for the default alternative 1 selected
		// during antlr code generation...
		(	'new' {strcat(pScopeReturnBuf," new");}
			(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
				LSQUARE RSQUARE  {strcat(pScopeReturnBuf,"[]");} )?
		|   
			'delete' {strcat(pScopeReturnBuf," delete");}
			(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
				LSQUARE RSQUARE  {strcat(pScopeReturnBuf,"[]");} )?
		|	
			LPAREN RPAREN  {strcat(pScopeReturnBuf,"()");}
		|	
			LSQUARE RSQUARE  {strcat(pScopeReturnBuf,"[]");}
		|
			{strcat(pScopeReturnBuf, reinterpret_cast<const char*>(LT(1)->getText(LT(1))->chars));}
			optor_simple_tokclass
		|
			{strcat(pScopeReturnBuf,"type-specifier()");}
			ts1 = type_specifier LPAREN RPAREN
		)
		{
		$oReturn = pScopeReturnBuf;
		}
	;


// optor_simple_tokclass
optor_simple_tokclass
	:
	//options{backtrack=true;}:
    	 PLUS|MINUS|STAR|DIVIDE|MOD|BITWISEXOR|AMPERSAND|BITWISEOR|TILDE|NOT|
	 SHIFTLEFT|SHIFTRIGHT|
	 ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
	 SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL|
	 EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
	 PLUSPLUS|MINUSMINUS|COMMA|POINTERTO|POINTERTOMBR
	
	
	;


/*
 * Lexer. 
 */


// Operators:

ASSIGNEQUAL     : '=' ;
COLON           : ':' ;
COMMA           : ',' ;
QUESTIONMARK    : '?' ;
SEMICOLON       : ';' ;
POINTERTO       : '->' ;

// DOT & ELLIPSIS are commented out since they are generated as part of
// the Number rule below due to some bizarre lexical ambiguity shme.
 DOT  :       '.' ;
 ELLIPSIS      : '...' ;

LPAREN          : '(' ;
RPAREN          : ')' ;
LSQUARE         : '[' ;
RSQUARE         : ']' ;
LCURLY          : '{' ;
RCURLY          : '}' ;

EQUAL           : '==' ;
NOTEQUAL        : '!=' ;
LESSTHANOREQUALTO     : '<=' ;
LESSTHAN              : '<' ;
GREATERTHANOREQUALTO  : '>=' ;
GREATERTHAN           : '>' ;

DIVIDE          : '/' ;
DIVIDEEQUAL     : '/=' ;
PLUS            : '+' ;
PLUSEQUAL       : '+=' ;
PLUSPLUS        : '++' ;
MINUS           : '-' ;
MINUSEQUAL      : '-=' ;
MINUSMINUS      : '--' ;
STAR            : '*' ;
TIMESEQUAL      : '*=' ;
MOD             : '%' ;
MODEQUAL        : '%=' ;
SHIFTRIGHT      : '>>' ;
SHIFTRIGHTEQUAL : '>>=' ;
SHIFTLEFT       : '<<' ;
SHIFTLEFTEQUAL  : '<<=' ;

AND            : '&&' ;
NOT            : '!' ;
OR             : '||' ;

AMPERSAND       : '&' ;
BITWISEANDEQUAL : '&=' ;
TILDE           : '~' ;
//BITWISEAND      : ' & ' ;
BITWISEOR       : '|' ;
BITWISEOREQUAL  : '|=' ;
BITWISEXOR      : '^' ;
BITWISEXOREQUAL : '^=' ;

//Zuo: the following tokens are come from cplusplus.g

POINTERTOMBR    : '->*' ;
DOTMBR          : '.*'  ;

SCOPE           : '::'  ;

Whitespace	
	:	
		(	// Ignore space
			Space
		|	// handle newlines
			(	'\r' '\n'	// MS
			|	'\r'		// Mac
			|	'\n'		// Unix 
			)	{/*newline();*/}
		|	// handle continuation lines
			(	'\\' '\r' '\n'	// MS
			|	'\\' '\r'		// Mac
			|	'\\' '\n'		// Unix 
			)	{printf("CPP_parser.g continuation line detected on line \%d\n",$line);
				deferredNewline();}
		)	
		{ $channel=HIDDEN;  }
	;

Comment  
	:	
		'/*'   
		(	{LA(2) != '/'}?=> '*'
		|	EndOfLine {deferredNewline();}
		|	~('*'| '\r' | '\n')
		)*
		'*/' { $channel=HIDDEN;  }
	;

CPPComment
	:	
		'//' (~('\n' | '\r'))* EndOfLine
 		{ $channel=HIDDEN; /*newline();*/}                     
	;

PREPROC_DIRECTIVE
	//options{paraphrase = 'a line directive';}
	@init { paraphrase_push("a line directive"); }
	@after { paraphrase_pop(); }
	:	
		'#' LineDirective
		{ $channel=HIDDEN; /*newline();*/} 
	;

fragment 
LineDirective
	:
		('line')?  // this would be for if the directive started '#line'
		(Space)+
		n=Decimal
		(Space)+
		(sl=StringLiteral)
		((Space)+ Decimal)*	// To support cpp flags (GNU)
		{
		process_line_directive((char*)$sl.text->chars, (char*)$n.text->chars);  // see main()
		}
		EndOfLine?
	;

fragment  
Space
	:	
			(' '|'\t' {tab();}|'\f')
	;

Pragma
	:	
		('#' 'pragma'	(	(EndOfContinuedLine)=>EndOfContinuedLine
						|	~('\r' | '\n')
						)*
		EndOfLine?
		)
		{ $channel=HIDDEN; /*newline();*/}
	;

Error
	:	
		('#' 'error'	(	(EndOfContinuedLine)=>EndOfContinuedLine
						|	~('\r' | '\n')
						)* EndOfLine
		EndOfLine?
		)
		{ $channel=HIDDEN; /*newline();*/}
	;


// Added by V3-Author to eliminate the need for a preprocessor
PreProcDirective
		:
			('#' 
				(Space)=> Space*
				(
					('ifdef')=> 'ifdef'	 		
				|	('ifndef')=> 'ifndef' 		
				|	('if')=> 'if' 	  		
				|	('elif')=> 'elif' 	 		
				|	('else')=> 'else' 	 		
				|	('endif')=> 'endif'	 			
				|	('undef')=> 'undef'    
				|	('define')=> 'define' 
				|	('exec_macro_expression')=> 'exec_macro_expression' 
				|	('include')=> 'include'
				|	('include_next')=> 'include_next'	
				|	('warning')=> 'warning' 
				)	
				
				(	(EndOfContinuedLine)=>EndOfContinuedLine
					|	~('\r' | '\n')
				)*
			EndOfLine?
			)
		{ $channel=HIDDEN; /*newline();*/}
		;

// Literals:

/*
 * Note that we do NOT handle tri-graphs nor multi-byte sequences.
 */

/*
 * Note that we can't have empty character constants (even though we
 * can have empty strings :-).
 */
CharLiteral
	:	
		'\'' ( Escape | UniversalCharacterName | ~('\''|'\\'|'\n'|'\r') ) '\''
	;

WCharLiteral
	:
		'L' CharLiteral
	;

/*
 * Can't have raw imbedded newlines in string constants.  Strict reading of
 * the standard gives odd dichotomy between newlines & carriage returns.
 * Go figure.
 */
StringLiteral
	:	
		'"'
		(	Escape
		|	UniversalCharacterName
		|	~('"'|'\\'|'\n'|'\r')
		)*
		'"'
	;

WStringLiteral
	:
		'L' StringLiteral
	;

fragment
EndOfContinuedLine
	:
		(//{dummyVar}?=> //added by V3-Author //options{generateAmbigWarnings = false;}:
			'\\' (Space)* '\r' '\n'	// MS
		|	'\\' (Space)* '\r'		// Mac
		|	'\\' (Space)* '\n'		// Unix 
		)	{deferredNewline();}
	;

fragment
EndOfLine
	:	
		(//{dummyVar}?=> //added by V3-Author //options{generateAmbigWarnings = false;}:
			'\r\n'  // MS
		|	'\r'    // Mac
		|	'\n'    // Unix
		)
	;

/*
 * Handle the various escape sequences.
 *
 * Note carefully that these numeric escape *sequences* are *not* of the
 * same form as the C language numeric *constants*.
 *
 * There is no such thing as a binary numeric escape sequence.
 *
 * Octal escape sequences are either 1, 2, or 3 octal digits exactly.
 *
 * There is no such thing as a decimal escape sequence.
 *
 * Hexadecimal escape sequences are begun with a leading \x and continue
 * until a non-hexadecimal character is found.
 *
 * No real handling of tri-graph sequences, yet.
 */

fragment
Escape  
	:	
		'\\'
		(// options{warnWhenFollowAmbig=false;}:
		  'a'
		| 'b'
		| 'f'
		| 'n'
		| 'r'
		| 't'
		| 'v'
		| '"'
		| '\''
		| '\\'
		| '?'
		| ('0'..'3') (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}:
		 Digit (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}:
		  Digit)? )?
		| ('4'..'7') (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}: 
		Digit)?
		| 'x' (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}:
		 HexadecimalDigit)+ //Digit | 'a'..'f' | 'A'..'F')+
		)
	;

// Numeric Constants: 


fragment
Digit
	:	
		'0'..'9'
	;

fragment
Decimal
	:	
		('0'..'9')+
	;

fragment
LongSuffix
	:	'l'
	|	'L'
	;

fragment
UnsignedSuffix
	:	'u'
	|	'U'
	;

fragment
FloatSuffix
	:	'f'
	|	'F'
	;

fragment
Exponent
	:	
		('e'|'E') ('+'|'-')? (Digit)+
	;

fragment
UniversalCharacterName
	:
		'\\u' HexQuad
	|	'\\U' HexQuad HexQuad
	;

fragment
HexQuad
	:
		HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit 
	;

fragment
HexadecimalDigit
	:
		('0'..'9'|'a'..'f'|'A'..'F')
	;

fragment
Vocabulary
	:	
		'\u0003'..'\u0377'
	;

Number
	:	
		( (Digit)+ ('.' | 'e' | 'E') )=> 
		(Digit)+
		( '.' (Digit)* (Exponent)? {$type = FLOATONE;} //Zuo 3/12/01
		| Exponent                 {$type = FLOATTWO;} //Zuo 3/12/01
		)                          //{_ttype = DoubleDoubleConst;}
		(FloatSuffix               //{_ttype = FloatDoubleConst;}
		|LongSuffix                //{_ttype = LongDoubleConst;}
		)?
	|	
		('...')=> '...'            {$type = ELLIPSIS;}
	|	
		'.'                        {$type = DOT;}
		(	(Digit)+ (Exponent)?   {$type = FLOATONE;} //Zuo 3/12/01
                                   //{_ttype = DoubleDoubleConst;}
			(FloatSuffix           //{_ttype = FloatDoubleConst;}
			|LongSuffix            //{_ttype = LongDoubleConst;}
			)?
		)?
	|	
		'0' ('0'..'7')*            //{_ttype = IntOctalConst;}
		(LongSuffix                //{_ttype = LongOctalConst;}
		|UnsignedSuffix            //{_ttype = UnsignedOctalConst;}
		)*                         {$type = OCTALINT;}
	|	
		'1'..'9' (Digit)*          //{_ttype = IntIntConst;}
		(LongSuffix                //{_ttype = LongIntConst;}
		|UnsignedSuffix            //{_ttype = UnsignedIntConst;}
		)*                         {$type = DECIMALINT;}  
	|	
		'0' ('x' | 'X') (HexadecimalDigit)+ //('a'..'f' | 'A'..'F' | Digit)+
                                   //{_ttype = IntHexConst;}
		(LongSuffix                //{_ttype = LongHexConst;}
		|UnsignedSuffix            //{_ttype = UnsignedHexConst;}
		)*                         {$type = HEXADECIMALINT;}   
	;

ID
	//options {testLiterals = true;}
	:
		(('asm'|'_asm'|'__asm') Whitespace )=>

		('asm'|'_asm'|'__asm') 
			(EndOfLine {deferredNewline();}
			|Space
			)+
		(
			LPAREN
				(	EndOfLine {deferredNewline();}	
				|	~(')' | '\r' | '\n')
				)*	
			RPAREN { $channel=HIDDEN; }
		|
			LCURLY
				(	EndOfLine {deferredNewline();}	
				|	~('}' | '\r' | '\n')
				)*	
			RCURLY { $channel=HIDDEN; }
		|
			// Single line asm statement
			(~('(' | ')' | '{' | '}' | '\n' | '\r' | ' ' | '\t' | '\f'))
			(~('(' | ')' | '{' | '}' | '\n' | '\r'))* (EndOfLine {/*newline();*/})?
			{ $channel=HIDDEN; }
		)
	|	
		('a'..'z'|'A'..'Z'|'_')
		('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
	;

fragment
OCTALINT:;

fragment
DECIMALINT:;

fragment
HEXADECIMALINT:;

fragment
FLOATONE:;

fragment
FLOATTWO:;
